package cn.edu.zut.soft.graduate.groupCenter.bo.Impl;

import cn.edu.zut.soft.basic.core.constant.Alternative;
import cn.edu.zut.soft.basic.core.model.bo.CommonResult;
import cn.edu.zut.soft.basic.core.model.dao.Criteria;
import cn.edu.zut.soft.basic.core.model.dao.Example;
import cn.edu.zut.soft.basic.core.model.pojo.Relation;
import cn.edu.zut.soft.graduate.base.bo.BasicBOImpl;
import cn.edu.zut.soft.graduate.base.dao.BasicDAO;
import cn.edu.zut.soft.graduate.core.constant.DeclareStatus;
import cn.edu.zut.soft.graduate.core.constant.InfoType;
import cn.edu.zut.soft.graduate.core.constant.Role;
import cn.edu.zut.soft.graduate.core.constant.config.IKEY;
import cn.edu.zut.soft.graduate.core.design.BasicInfoStrategy;
import cn.edu.zut.soft.graduate.core.design.InfoStrategy;
import cn.edu.zut.soft.graduate.core.model.Impl.CreateGroup;
import cn.edu.zut.soft.graduate.core.model.Impl.Group;
import cn.edu.zut.soft.graduate.core.model.Impl.Identity;
import cn.edu.zut.soft.graduate.core.model.Impl.Info;
import cn.edu.zut.soft.graduate.core.query.DeclareQuery;
import cn.edu.zut.soft.graduate.core.query.GroupQuery;
import cn.edu.zut.soft.graduate.core.query.InfoQuery;
import cn.edu.zut.soft.graduate.core.vo.LoginVO;
import cn.edu.zut.soft.graduate.groupCenter.bo.GroupBO;
import cn.edu.zut.soft.graduate.groupCenter.bo.InviteBO;
import cn.edu.zut.soft.graduate.groupCenter.dao.GroupDAO;
import cn.edu.zut.soft.graduate.groupCenter.excetion.GroupException;
import cn.edu.zut.soft.graduate.groupCenter.op.GroupOP;
import cn.edu.zut.soft.graduate.groupCenter.pojo.SaveUserGroup;
import cn.edu.zut.soft.graduate.massageCenter.bo.MessageBO;
import cn.edu.zut.soft.graduate.massageCenter.generator.Impl.InviteOPGroupBuilder;
import cn.edu.zut.soft.graduate.topicCenter.bo.CompanyProjectRequestBO;
import cn.edu.zut.soft.graduate.topicCenter.bo.DeclareBO;
import cn.edu.zut.soft.graduate.userCenter.bo.IdentityBO;
import cn.edu.zut.soft.graduate.userCenter.bo.InfoBO;
import cn.edu.zut.soft.graduate.userCenter.dao.InfoDAO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;

/**
 * @author chuchuang
 * @date 16/11/20
 */
@Service
public class GroupBOImpl extends BasicBOImpl<Group, GroupQuery> implements GroupBO {

    @Autowired
    private GroupDAO<Group> groupDAO;

    @Autowired
    private InfoBO infoBO;

    @Autowired
    private InfoDAO<Info> infoDAO;

    @Autowired
    private IdentityBO identityBO;

    @Autowired
    private GroupOP groupOP;

    @Autowired
    private MessageBO messageBO;

    @Autowired
    private DeclareBO declareBO;

    @Autowired
    private InviteBO inviteBO;

    @Autowired
    private CompanyProjectRequestBO companyProjectRequestBO;

    @Override
    protected BasicDAO<Integer, Group> getDAO() {
        return groupDAO;
    }

    @Override
    protected List<Criteria> Query(GroupQuery groupQuery) {
        Criteria criteria = new Criteria();
        if (groupQuery.getId() != null) {
            criteria.andEqualTo("id", groupQuery.getId());
        }
        if (groupQuery.getRole() != null) {
            criteria.andEqualTo("`role`", groupQuery.getRole());
        }
        if (groupQuery.getStatus() != null) {
            criteria.andEqualTo("`status`", groupQuery.getStatus());
        }
        if (groupQuery.getIdentityId() != null) {
            criteria.andEqualTo("identity_id", groupQuery.getIdentityId());
        }
        if (CollectionUtils.isNotEmpty(groupQuery.getIds())){
            criteria.andIn("id",groupQuery.getIds());
        }
        if (groupQuery.getDel() != null) {
            criteria.andEqualTo("del", groupQuery.getDel());
        } else {
            criteria.andEqualTo("del", IKEY.ZERO);
        }
        return Collections.singletonList(criteria);
    }

    @Override
    @Transactional
    public boolean associationIDGroup(SaveUserGroup saveUserGroup, Relation relation) {
        Assert.notNull(saveUserGroup);
        Assert.notNull(relation);
        Assert.notNull(saveUserGroup.getIdentity());
        Assert.notNull(saveUserGroup.getGroup());

        InfoQuery infoQuery = new InfoQuery();
        infoQuery.setInfoType(InfoType.Group);
        infoQuery.setKey(IKEY.GROUP);
        infoQuery.setIdentityId(saveUserGroup.getIdentity().getId());
        List list = infoBO.findByQuery(infoQuery).getData();
        if (list != null && list.size() > IKEY.ZERO) {
            throw GroupException.create("已经存在小组 list = " + list);
        }
        Info info = new Info();
        info.setIdentityId(saveUserGroup.getIdentity().getId());
        info.setIdentityName(saveUserGroup.getIdentity().getName());
        info.setIdentityRole(saveUserGroup.getIdentity().getRole());
        info.setType(InfoType.Group.name());
        info.setKey(IKEY.GROUP);
        info.setValue("" + saveUserGroup.getGroup().getId());
//        infoDAO.insert(info);
        infoBO.save(info, saveUserGroup.getUser().getName());

        return info.getId() != null;
    }

    @Override
    @Transactional
    public Group joinGroup(LoginVO loginVO, Integer groupId, Alternative alternative) {
        Identity identity = identityBO.get(loginVO.getId());
        Assert.notNull(identity);
        Assert.isTrue(identity.getDel() == 0, "账号错误");
        Group group = get(groupId);
        if (Alternative.YES == alternative) {
            Assert.isTrue(group.getCount() < IKEY.GROUP_COUNT_MAX, "小组成员已经存在3个人");
        }
        Assert.notNull(group, "小组不存在");
        Assert.isTrue(!group.getIdentityId().equals(loginVO.getId()), "组长不能重复加入自己小组");
        if (Alternative.YES == alternative) {
            //申请校外课题处理
            Assert.isNull(companyProjectRequestBO.isQualified(loginVO), "小组已经申请校外课题,无法加入小组");
            DeclareQuery declareQuery = new DeclareQuery();
            declareQuery.setDeclareStatusList(Arrays.asList(DeclareStatus.ING, DeclareStatus.YES));
            declareQuery.setGroupId(group.getId());
            int count = declareBO.countByQuery(declareQuery);
            Assert.isTrue(count == 0, "小组状态已经提出课题申请,无法加入");
            return groupOP.JoinGroup(loginVO, identity, group);
        }
        //记录拒绝或者同意信息
        messageBO.AssemblyAndSend(loginVO, Collections.singletonList(group.getIdentityId()), InviteOPGroupBuilder.createBuilder(alternative));

        return group;
    }

    @Override
    @Transactional
    public Group assignGroupTea(LoginVO loginVO, Integer groupId, Integer id) {
        InfoQuery infoQuery = new InfoQuery();
        infoQuery.setIdentityId(id);
        infoQuery.setInfoType(InfoType.Group);
        infoQuery.setKey(IKEY.GROUP);
        Assert.isTrue(infoBO.countByQuery(infoQuery) == IKEY.ZERO ,"当前用户已经存在小组,无法分配");
        Group group = get(groupId);
        group.setCount(group.getCount()+1);
        this.afterUpdate(group,loginVO.getName());
        getDAO().updateByPrimaryKeySelective(group);
        infoBO.save(new BasicInfoStrategy(InfoType.Group,IKEY.GROUP,groupId.toString()),id,loginVO.getName());
        return group;
    }

    @Override
    @Transactional
    public Group unAssignGroupTea(LoginVO loginVO, Integer groupId, Integer id) {
        InfoQuery infoQuery = new InfoQuery();
        infoQuery.setIdentityId(id);
        infoQuery.setInfoType(InfoType.Group);
//        infoQuery.setKey(IKEY.GROUP);
        List<Info> infoList = infoBO.queryByUser(id);
//        Assert.isTrue(infoList.size() == 1 ,"当前用户不存在小组");
        Group group = get(groupId);
        group.setCount(group.getCount()-1);
        this.afterUpdate(group,loginVO.getName());
        getDAO().updateByPrimaryKeySelective(group);
        for (Info info:infoList) {
            infoBO.delete(info.getId(), loginVO.getName());
        }
        return group;
    }

    @Override
    @Transactional
    public CommonResult<List<SaveUserGroup>> batchAssociationIDGroup(LoginVO loginVO, Integer groupId, Collection<Integer> ids) {
        return null;
    }

    @Override
    @Transactional
    public Group userCreateGroup(CreateGroup createGroup) {
        Assert.notNull(createGroup);
        //修改小组负责人
        if (Role.Runner.user == createGroup.getRunner()) {
            Assert.notNull(createGroup.getUser(), "user is null");
            Assert.notNull(createGroup.getUser().getId(), "user.is is null");
            createGroup.setOwner(createGroup.getUser().getId());
        }

        //获取主要负责人信息
        Assert.notNull(createGroup.getOwner(), "owner is error");
        Identity identity = identityBO.get(createGroup.getOwner());
        Assert.notNull(identity, "用户不存在:id = " + createGroup.getOwner());
        //验证角色
        Assert.isTrue(createGroup.getRole() != null && createGroup.getRole() == identity.getRole(), "role 不一致");
        //创建小组
        return groupOP.OwnerCreateGroup(createGroup.getUser(), identity, createGroup.getUser().getName());
    }

    @Override
    @Transactional
    public Group delete(LoginVO loginVO, Integer id) {
        Assert.notNull(loginVO);
        Assert.notNull(id);
        Group group = getDAO().selectByPrimaryKey(id);
        Assert.notNull(group, "小组不存在");
        Assert.isTrue(group.getDel() == IKEY.ZERO, "小组已删除,不可以重复操作");

        //不准删除的逻辑验证
        //若提交了公司项目申请,则不能删除小组。没有被拒绝
        Assert.isTrue(!companyProjectRequestBO.isSendCompany(group.getId()), "小组已经申报校外题目,无法解散,请联系管理员");

        List<Info> infoList = infoBO.queryByInfoStrategy(Arrays.<InfoStrategy>asList(
                new BasicInfoStrategy(InfoType.Group, IKEY.GROUP, "" + group.getId()),
                new BasicInfoStrategy(InfoType.Group, IKEY.GroupLeader, "" + group.getId())));
        DeclareQuery declareQuery = new DeclareQuery();
        declareQuery.setDel(IKEY.ZERO);
        declareQuery.setGroupId(group.getId());
        declareQuery.setDeclareStatusList(Arrays.asList(DeclareStatus.ING, DeclareStatus.YES));
        Assert.isTrue(declareBO.countByQuery(declareQuery) == 0, "小组存在申报或申报成功的课题,无法解散课题");

        //删除小组关联申报
        declareBO.deleteByGroupId(group.getId(), loginVO.getName());
        //删邀请关联表
        inviteBO.deleteByGroupId(loginVO, group.getId());
        List<Integer> ids = new ArrayList<>(infoList.size());
        CollectionUtils.collect(infoList, new Transformer() {
            @Override
            public Object transform(Object o) {
                return ((Info) o).getId();
            }
        }, ids);
        Info info = new Info();
        info.setDel(-1);
        info.setUpdateAuthor(loginVO.getName());
        Example example = new Example();
        example.createCriteria().andIn("id", ids);
        //逻辑删除info信息
        infoDAO.updateByExampleSelective(info, example);
        group.setDel(-1);
        group.setUpdateAuthor(loginVO.getName());
        getDAO().updateByPrimaryKeySelective(group);
        return group;
    }

    @Override
    public CommonResult<List<Group>> findNoIssueStuGroup(GroupQuery groupQuery) {
        //一种投机的算法
        List<Info> groupList = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.Group, IKEY.GroupLeader, null)));
        List<Info> topicList = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.TOPIC,IKEY.TopicId,null)));
        List<Info> teaList = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.Tea,IKEY.Guide,null)));
        //特殊处理,
        Map<Integer,String> groupMap = new HashMap<>(groupList.size());
        for (Info info : groupList){
            groupMap.put(info.getIdentityId(),info.getValue());
        }
        for (Info info : topicList){
            groupMap.remove(info.getIdentityId());
        }
        for (Info info : teaList){
            groupMap.remove(info.getIdentityId());
        }
        List<Integer> ids = new ArrayList<>(groupMap.size());
        for (Map.Entry<Integer,String> me : groupMap.entrySet()){
            ids.add(Integer.parseInt(me.getValue()));
        }
        if (CollectionUtils.isEmpty(ids)){
            return CommonResult.successReturn(Collections.<Group>emptyList());
        }
        groupQuery.setIds(ids);
        return findByQuery(groupQuery);
    }

    @Override
    public CommonResult<List<Group>> findAllGroup(){
//        List<Info> infoList = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.Group, IKEY.GroupLeader, null)));
//        Map<Integer,String> groupMap = new HashMap<>(infoList.size());
//        for (Info info : infoList){
//            groupMap.put(info.getIdentityId(),info.getValue());
//        }
//        List<Integer> ids = new ArrayList<>(infoList.size());
//        for (Map.Entry<Integer,String> me : groupMap.entrySet()){
//            ids.add(Integer.parseInt(me.getValue()));
//        }
//        if (CollectionUtils.isEmpty(ids)){
//            return CommonResult.successReturn(Collections.<Group>emptyList());
//        }
//        groupQuery.setIds(ids);
//        return findByQuery(groupQuery);
        return null;
    }

    @Override
    public CommonResult<Group> distributionReplyTeaGroup(LoginVO loginVO, Integer groupId, Integer disGroupId) {
        CommonResult<Group> result = null;
        if (loginVO == null || groupId == null || disGroupId == null){
            result = new CommonResult<Group>(false, "System error!");
            return result;
        }
        //校验是否是管理员身份
        Boolean checkAdmin = checkAdminRole(loginVO.getId());
        if (checkAdmin){
            Group group = groupDAO.selectByPrimaryKey(groupId);
//            if (group.get)
        }else{

        }

        return result;
    }

    /**
     * <p>功能描述：校验该角色是否是管理员 不是管理员不可操作</p>
     * <p>创建人：yangxiaotian</p>
     * <p>创建日期：2017-05-03 00:17:42</p>
     *
     * @param id
     * @return
     */
    private Boolean checkAdminRole (Integer id){
        Boolean result = false;
        if (id == null){
            return result;
        }
        Example example = new Example();
        example.createCriteria().andEqualTo("key", IKEY.ADMIN).andEqualTo("del", "0").andEqualTo("identity_id", id);
        List<Info> adminResult = infoDAO.selectByExample(example);
        if (CollectionUtils.isNotEmpty(adminResult)){
            for (Info info : adminResult){
                if (info.getKey().equals(IKEY.ADMIN)){
                    result = true;
                }
            }
        }
        return result;
    }
}
